package com.houweishi.module.salary.service.impl;

import com.houweishi.common.core.domain.entity.SysDept;
import com.houweishi.common.core.domain.entity.SysUser;
import com.houweishi.common.utils.DateUtils;
import com.houweishi.module.clockingcount.domain.BizClockingCount;
import com.houweishi.module.clockingcount.mapper.BizClockingCountMapper;
import com.houweishi.module.salary.domain.BizSalary;
import com.houweishi.module.salary.mapper.BizSalaryMapper;
import com.houweishi.module.salary.service.IBizSalaryService;
import com.houweishi.module.staff.domain.BizStaff;
import com.houweishi.module.staff.mapper.BizStaffMapper;
import com.houweishi.system.domain.SysPost;
import com.houweishi.system.mapper.SysDeptMapper;
import com.houweishi.system.mapper.SysPostMapper;
import com.houweishi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 薪资Service业务层处理
 * 
 * @author houweishi
 * @date 2023-03-04
 */
@Service
public class BizSalaryServiceImpl implements IBizSalaryService 
{
//    @Autowired
    @Resource
    private BizSalaryMapper bizSalaryMapper;

    @Resource
    private BizClockingCountMapper bizClockingCountMapper;

    @Resource
    private BizStaffMapper bizStaffMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysPostMapper sysPostMapper;

    @Resource
    private SysDeptMapper sysDeptMapper;


    /**
     * 查询薪资
     * 
     * @param id 薪资主键
     * @return 薪资
     */
    @Override
    public BizSalary selectBizSalaryById(Long id)
    {
        return bizSalaryMapper.selectBizSalaryById(id);
    }

    /**
     * 查询薪资列表
     * 
     * @param bizSalary 薪资
     * @return 薪资
     */
    @Override
    public List<BizSalary> selectBizSalaryList(BizSalary bizSalary)
    {

        return bizSalaryMapper.selectBizSalaryList(bizSalary);
    }

    /**
     * 新增薪资
     * 
     * @param bizSalary 薪资
     * @return 结果
     */
    @Override
    public int insertBizSalary(BizSalary bizSalary)
    {
        bizSalary.setCreateTime(DateUtils.getNowDate());
        return bizSalaryMapper.insertBizSalary(bizSalary);
    }

    /**
     * 修改薪资
     * 
     * @param bizSalary 薪资
     * @return 结果
     */
    @Override
    public int updateBizSalary(BizSalary bizSalary)
    {
        bizSalary.setUpdateTime(DateUtils.getNowDate());
        int result = bizSalaryMapper.updateBizSalary(bizSalary);

        return result;
    }

    /**
     * 批量删除薪资
     * 
     * @param ids 需要删除的薪资主键
     * @return 结果
     */
    @Override
    public int deleteBizSalaryByIds(Long[] ids)
    {
        return bizSalaryMapper.deleteBizSalaryByIds(ids);
    }

    /**
     * 删除薪资信息
     * 
     * @param id 薪资主键
     * @return 结果
     */
    @Override
    public int deleteBizSalaryById(Long id)
    {
        return bizSalaryMapper.deleteBizSalaryById(id);
    }

    /**
     * 一键生成工资表基本信息
     *
     * @param bizSalary 薪资
     * @return 结果
     */
    @Transactional
    @Override
    public int insertAndCountBizSalary(BizSalary bizSalary)
    {
        //拿到上个月所有员工的考勤记录
        BizClockingCount bizClockingCount = new BizClockingCount();
        List<BizClockingCount> clockingCountList = bizClockingCountMapper.selectBizClockingCountListByLastMonth(bizClockingCount);

        int result = 1;
        // list根据StaffId去重,得到参与考勤的所有人
        List<BizClockingCount> list = clockingCountList.stream().filter(distinctByKey(e -> e.getStaffId())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(list)){
            list.forEach(count->{
                BizSalary bizSalary1 = new BizSalary();
                //拿到员工信息
                bizSalary1.setStaffId(count.getStaffId());
                bizSalary1.setStaffName(count.getStaffName());


                //通过员工表拿到相应信息
                BizStaff staff = bizStaffMapper.selectBizStaffById(count.getStaffId());
                // bizSalary1.setEntryTime(staff.getEntryTime());
//                bizSalary1.setPostName(staff.getPost());


                //计算工龄工资
                Date day=new Date();
                int year = 1;
                Calendar cal = Calendar.getInstance();//当前时间的年月日
                cal.setTime(day);
                int nowYear = cal.get(Calendar.YEAR);
                int nowMonth = cal.get(Calendar.MONTH);
//                int nowDay = cal.get(Calendar.DAY_OF_MONTH);
                //开始工作时间的年月日
                // cal.setTime(staff.getEntryTime());
                int workYear = cal.get(Calendar.YEAR);
                int workMonth = cal.get(Calendar.MONTH);
//                int workDay = cal.get(Calendar.DAY_OF_MONTH);
                //得到工龄
                year = nowYear - workYear; //得到年差
                //若目前月数少于开始工作时间的月数，年差-1
                if (nowMonth < workMonth){
                    year  = year - 1;
                }
//                else if (nowMonth == workMonth){
//                    //当月数相等时，判断日数，若当月的日数小于开始工作时间的日数，年差-1
//                    if (nowDay < workDay){
//                        year = year - 1;
//                    }
//                }
                int a = year * 200;
                String sum = String.valueOf(a);
                BigDecimal salary = new BigDecimal(sum);
                bizSalary1.setSenioritySalary(salary);


                //上月考勤打卡天数
                BizClockingCount bizClockingCount1 = new BizClockingCount();
                bizClockingCount1.setStaffId(count.getStaffId());
                List<BizClockingCount> bizClockingCountList = bizClockingCountMapper.selectBizClockingCountListByLastMonth(bizClockingCount1);
                int clockSum = bizClockingCountList.size();
                bizSalary1.setAttendanceDays(Long.valueOf(clockSum));

                //上月实际天数（每月一号计算上个月的考勤)
                Calendar ca = Calendar.getInstance(TimeZone.getTimeZone("GMT+8")); // 设置时区
                SimpleDateFormat oSdf = new SimpleDateFormat ("yyyy-MM-dd");
                String format = oSdf.format(new Date());
                try {
                    ca.setTime(oSdf.parse(format)); // 设置时间
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                int thisYear = ca.get(Calendar.YEAR);
                int thisMonthSum = ca.get(Calendar.DAY_OF_MONTH); // 得到当月
                ca.add(Calendar.MONTH, -1); // 得到上月月份
                int lastMonthSum = ca.getActualMaximum(Calendar.DAY_OF_MONTH); // 得到上月总天数
                int sum1 = lastMonthSum - 4;//上月实际需要出勤天数（未减法假）


//                //基本薪资默认1610
//                String str = "1610";
//                BigDecimal base = new BigDecimal(str);
//                bizSalary1.setBaseSalary(base);


                SysUser sysUser = new SysUser();
                sysUser.setStaffId(count.getStaffId());
                List<SysUser> userList = sysUserMapper.selectUserList(sysUser);
                SysUser sysUser1 = userList.get(0);

                //获取岗位津贴，id，名称...等岗位绑定的基础信息
                List<Long> postIdList = sysPostMapper.selectPostListByUserId(sysUser1.getUserId());
                Long postId = postIdList.get(0);
                SysPost sysPost = sysPostMapper.selectPostById(postId);

                bizSalary1.setPostId(sysPost.getPostId());
                bizSalary1.setPostName(sysPost.getPostName());
                bizSalary1.setBaseSalary(sysPost.getBaseSalary());//基本工资
                bizSalary1.setPostSubsidy(sysPost.getPostSubsidy());//岗位津贴
                bizSalary1.setSenioritySalary(sysPost.getSenioritySalary());//工龄工资
                bizSalary1.setSkillsAssessSalary(sysPost.getSkillsAssessSalary());//技能考核工资
                bizSalary1.setManageAssessSalary(sysPost.getManageAssessSalary());//管理考核工资
                bizSalary1.setMeritSalary(sysPost.getMeritSalary());//绩效工资
                bizSalary1.setSafetyAward(sysPost.getSafetyAward());//安全奖
                bizSalary1.setFullTimeSalary(sysPost.getFullTimeSalary());//全勤奖

                //获取部门id和部门名称
                SysDept dept = sysDeptMapper.selectDeptById(sysUser1.getDeptId());
                bizSalary1.setDeptId(dept.getDeptId());
                bizSalary1.setDeptName(dept.getDeptName());


                //上个月的最后一天(薪资计算截止日期) LocalDate转date类型
                LocalDate salaryTime = LocalDate.now().minusMonths(1L).with(TemporalAdjusters.lastDayOfMonth());
                ZoneId zone = ZoneId.systemDefault();
                //将此日期与午夜时间组合在一起，以便在此日期开始时创建LocalDateTime，例如：2017-02-03T00:00
                Instant instant = salaryTime.atStartOfDay().atZone(zone).toInstant();
                Date date = Date.from(instant);
                bizSalary1.setSalaryTime(date);


                bizSalary1.setCreateTime(DateUtils.getNowDate());
                bizSalaryMapper.insertBizSalary(bizSalary1);
            });
        }
        return result;
    }


    /**
     * 〈功能描述〉属性去重
     *
     * @param keyExtractor
     * @return java.util.function.Predicate<T>
     * @throws
     * @author caic
     * @see
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }


    //工资说明：出勤工资=（基本工资+岗位津贴+工龄工资+技能考核+管理考核+安全奖+绩效奖+全勤奖）/30天*出勤天数；
    // 应发工资=出勤工资+专项考核；实发工资=应发工资-应扣工资；单位：元。
    /**
     * 薪资！！！（无值则前端默认传0.00）
     *
     * @param bizSalary 薪资
     * @return 结果
     */
    @Transactional
    @Override
    public int updateBizSalary2(BizSalary bizSalary){

        bizSalary.setUpdateTime(DateUtils.getNowDate());
        int result = bizSalaryMapper.updateBizSalary(bizSalary);

        BizSalary bizSalary1 = bizSalaryMapper.selectBizSalaryById(bizSalary.getId());

        List<BigDecimal> list = new ArrayList<>();
        List<BigDecimal> list2 = new ArrayList<>();

        BigDecimal baseSalary = bizSalary1.getBaseSalary();//基本工资
        BigDecimal postSubsidy = bizSalary1.getPostSubsidy();//岗位津贴
        BigDecimal senioritySalary = bizSalary1.getSenioritySalary();//工龄工资
        BigDecimal skillsAssessSalary = bizSalary1.getSkillsAssessSalary();//技能考核工资
        BigDecimal manageAssessSalary = bizSalary1.getManageAssessSalary();//管理考核工资
        BigDecimal meritSalary = bizSalary1.getMeritSalary();//绩效工资
        BigDecimal safetyAward = bizSalary1.getSafetyAward();//安全奖
        BigDecimal fullTimeSalary = bizSalary1.getFullTimeSalary();//全勤奖

        list.add(baseSalary);
        list.add(postSubsidy);
        list.add(senioritySalary);
        list.add(skillsAssessSalary);
        list.add(manageAssessSalary);
        list.add(meritSalary);
        list.add(safetyAward);
        list.add(fullTimeSalary);

        //求和（理论上的最高月薪）
        BigDecimal salary = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        String strSalary = salary.toString();
        BigDecimal salary1 = new BigDecimal(strSalary);

        //每月满勤固定按26计算
        String strMonth = String.valueOf(26);
        BigDecimal month = new BigDecimal(strMonth);

        //拿到相应的考勤打卡天数
        String strClockDays = String.valueOf(bizSalary1.getAttendanceDays());
        BigDecimal days = new BigDecimal(strClockDays);

        //出勤工资，四舍五入保留两位小数（向上取整）
        BigDecimal salary2 = salary1.divide(month,2,BigDecimal.ROUND_HALF_UP).multiply(days);
        String strSalary2 = salary2.toString();
        BigDecimal salary3 =  new BigDecimal(strSalary2);

        //应发工资=出勤工资+专项考核
        String strSpecialAssess = bizSalary1.getSpecialAssess().toString();
        BigDecimal specialAssess = new BigDecimal(strSpecialAssess);
        BigDecimal salary4 = salary3.add(specialAssess);
        String strSalary4 = salary4.toString();
        BigDecimal salary5 =  new BigDecimal(strSalary4);

        //实发工资=应发工资-扣款项
        BigDecimal socialSecurity = bizSalary1.getSocialSecurity();//社保
        BigDecimal personalIncomeTax = bizSalary1.getPersonalIncomeTax();//个人所得税
        BigDecimal forfeit = bizSalary1.getForfeit();//罚款
        BigDecimal other = bizSalary1.getOther();//其他

        list2.add(socialSecurity);
        list2.add(personalIncomeTax);
        list2.add(forfeit);
        list2.add(other);

        //应扣款
        BigDecimal deductible = list2.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        String strDeductible = deductible.toString();
        BigDecimal chargeBack = new BigDecimal(strDeductible);
        BigDecimal netSalary = salary5.subtract(chargeBack);


        bizSalary1.setAttendanceSalary(salary2);
        bizSalary1.setWagesPayable(salary4);
        bizSalary1.setNetSalary(netSalary);

        bizSalaryMapper.updateBizSalary(bizSalary1);
        return result;
    }


    /**
     * 根据薪资计算截止日期查询薪资列表
     *
     * @param bizSalary 薪资
     * @return 薪资
     */
    @Override
    public List<BizSalary> selectBizSalaryListBySalaryTime(BizSalary bizSalary)
    {

        return bizSalaryMapper.selectBizSalaryListBySalaryTime(bizSalary);
    }
}
